/**
 * Created by xinxinran on 2017/1/1.
 */
'use strict';

const commonUtil = require('../utils/commonUtil'),
    loggerUtil = require('../utils/loggerUtil'),
    beanUtil = require('../utils/beanUtil');
let __super, __extend, __instanceof, __proxy, __isSubClassOf,
    BaseComponent, BaseService, BaseSocketService, BaseDao, ResponseTemplate;

function createClass(configureObj, superClass){
    const F = function () {
        const args = arguments;
        commonUtil.each(this._fullInits, commonUtil.scopeProxy(function (idx, initfn) {
            initfn.apply(this, args);
        }, this));
    };
    let superObj = superClass;
    if(typeof(superClass) === 'function'){
        superObj = superClass.prototype;
    }
    if(superClass){
        F.prototype = commonUtil.extendObj({}, superObj, configureObj);
        F.prototype._superClass = typeof(superClass) === 'function'? superClass : superClass.constructor;
    }else{
        F.prototype = configureObj;
    }

    F.prototype._fullInits = F.prototype._superClass ? F.prototype._superClass.prototype._fullInits.slice() : [];
    F.prototype.init && F.prototype._fullInits.push(F.prototype.init);

    F.prototype._myClass = F;
    F.prototype.instanceOf = __instanceof;
    F.prototype._super = __super;
    F.prototype.constructor = F;

    F.extend = __extend;
    F.aspectProxy = __proxy;
    F.isSubClassOf = __isSubClassOf;
    F.toString = function(){
        return F.prototype._fullInits.join('\n\n')
    };

    return F;
}


__super = function(fnName){ //TODO 考虑多层级关系
    let targetPrototype;
    if(targetPrototype = this._myClass.prototype._superClass){
        targetPrototype = targetPrototype.prototype;
    }else{
        targetPrototype = this._myClass.prototype;
    }
    if(targetPrototype[fnName]) {
        return targetPrototype[fnName].apply(this, Array.prototype.slice.call(arguments).slice(1));
    }
};

__extend = function(subClass){
    return typeof(subClass) === 'function' ? createClass(subClass.prototype, this) : createClass(subClass, this);
};

__instanceof = function(someClass){
    let tmpConstructor = this.constructor;
    if(!someClass){
        return false;
    }
    if(someClass === Object){
        return true;
    }
    if(typeof someClass !== 'function'){
        someClass = someClass.constructor;
    }
    while(tmpConstructor){
        if(tmpConstructor === someClass){
            return true;
        }else{
            tmpConstructor = tmpConstructor.prototype._superClass;
        }
    }
    return false;
};

__isSubClassOf = function(someClass){
    let tmpConstructor = this;
    if(!someClass){
        return false;
    }
    if(someClass === Object){
        return true;
    }
    if(typeof someClass !== 'function'){
        someClass = someClass.constructor;
    }
    while(tmpConstructor){
        if(tmpConstructor === someClass){
            return true;
        }else{
            tmpConstructor = tmpConstructor.prototype._superClass;
        }
    }
    return false;
};

ResponseTemplate = createClass({
    init : function(tplObject){
        this.templateObject = tplObject;
        this.setCode = null;
        this.setResult = null;
        this.setMessage = null;
        this.codeRoad = null;
        this.resultRoad = null;
        this.messageRoad = null;
    },
    markCode : function(codePath){
        const _this = this;
        this.codeRoad = codePath.split('.');
        this.setCode = function(obj, code){
            let codeRoad = _this.codeRoad.slice(),
                trueAttr = codeRoad.pop(), nowTarget = obj;

            commonUtil.each(codeRoad, function(_, attrName){
                if(!nowTarget[attrName]){
                    nowTarget[attrName] = {};
                }
                nowTarget = nowTarget[attrName];
            });

            nowTarget[trueAttr] = code;
        };

        return this;
    },
    markResult : function(resultPath){
        const _this = this;
        this.resultRoad = resultPath.split('.');
        this.setResult = function(obj, result){
            let resultRoad = _this.resultRoad.slice(),
                trueAttr = resultRoad.pop(), nowTarget = obj;

            commonUtil.each(resultRoad, function(_, attrName){
                if(!nowTarget[attrName]){
                    nowTarget[attrName] = {};
                }
                nowTarget = nowTarget[attrName];
            });

            if(trueAttr){
                nowTarget[trueAttr] = result;
            }else{
                Object.assign(nowTarget, result);
            }
        };

        return this;
    },
    markMessage : function(messagePath){
        const _this = this;
        this.messageRoad = messagePath.split('.');
        this.setMessage = function(obj, message){
            let messageRoad = _this.messageRoad.slice(),
                trueAttr = messageRoad.pop(), nowTarget = obj;

            commonUtil.each(messageRoad, function(_, attrName){
                if(!nowTarget[attrName]){
                    nowTarget[attrName] = {};
                }
                nowTarget = nowTarget[attrName];
            });

            nowTarget[trueAttr] = message;


        };

        return this;
    },
    getObject : function(){
        return commonUtil.extendObj({}, this.templateObject)
    }
});

BaseComponent = createClass({

});

BaseService = BaseComponent.extend({
    responseTemplate : new ResponseTemplate({})
        .markCode('code')
        .markMessage('msg')
        .markResult('body'),
    getRespTpl : function(){
        return this.responseTemplate;
    },
    beanLinkTo : function(beanName){
        return `$->${beanName}`;
    },
    preProcessResult : function(result){
        return result;
    }
});

BaseDao = BaseComponent.extend({
    generateId : function(){
        return commonUtil.uuid().replace('-', '');
    }
});

BaseSocketService = BaseService.extend({
    responseTemplate : new ResponseTemplate({})
        .markCode('code')
        .markMessage('message')
        .markResult(''),
    preProcessResult : function(result){
        if(!result){
            return {code : 0, result};
        }
        if(typeof result !== 'object'){
            result = {result};
        }
        if(!+result.code){
            result.code = 0;
        }
        return result;
    }
});

module.exports = {
    BaseComponent,
    BaseService,
    BaseSocketService ,
    BaseDao
};